/*
 * @Author: fu.lanyun
 * @Date: 2018-11-02 10:35:46
 * @Desc: 流程图绘制页面
 */
import React, { PureComponent } from "react";
import { Modal, Spin, message } from "antd";
import { connect } from "dva";
import router from "umi/router";
import FlowEditor from "components/g6edit";
import CanvasSelected from "components/flowdetailpannel/CanvasSelected";
import EdgeSelected from "components/flowdetailpannel/EdgeSelected";
import NodeSelected from "components/flowdetailpannel/NodeSelected";
import GroupSelected from "components/flowdetailpannel/GroupSelected";

import { modelJsonProperties } from "components/g6edit/structureData";
import { getViewPortHeight, openNotificationWithIcon } from "utils/comm";
import { getModelForms } from "components/flowdetailpannel/FlowParameters";
import {
  extractVarCodesFromTimeoutSetting,
  getCodes,
  setUpRef,
} from "./Tools/varRefHelper";
import {
  validateTimeoutSettings,
  getTimeoutErrorInfo,
} from "./Tools/alertValidationHelper";

import {GroupCheck} from './Tools/GroupCheck'

import styles from "./index.less";
// import { cosh } from "core-js/core/number";

const pattern = /^[a-zA-Z][a-zA-Z0-9_]*$/;
const modePattern = /^[a-zA-Z_][a-zA-Z_0-9-]*$/;

const checkList = [
  { key: "name", msg: "流程名称不能为空" },
  { key: "key", msg: "流程编码不能为空" },
  { key: "appId", msg: "请选择所属应用" },
  { key: "busiId", msg: "请选择所属业务" },
];

const titleObj = {
  userTask: "用户任务",
  serviceTask: "服务任",
  scriptTask: "脚本任务",
  eventStart: "开始事件",
  eventEnd: "结束事件",
  gatewayInclude: "包含网关",
  gatewayParallel: "并行网关",
  gatewayExclude: "排他网关",
  "flow-polyline-round": "连线",
};

@connect(({ appListMenu, loading, FlowChart, FlowHandle }) => ({
  loading,
  menuAppStore: appListMenu,
  FlowChartStore: FlowChart,
  FlowHandleStore: FlowHandle,
}))
class FlowChart extends PureComponent {
  constructor(props) {
    super(props);
    this.openNotificationWithIcon = openNotificationWithIcon.bind(this);
    this.getViewPortHeight = getViewPortHeight;
    this.state = {
      modelJson: {},
      modelProperties: modelJsonProperties,
      sampleDetailData: {},
      flowHeight: "auto",
      modelVariableRef: {}, // { code: [ nodeModel ] }
      modelForms: [],
    };
    setUpRef(this);
    // window.temp = this;
  }

  componentDidMount() {
    window.addEventListener("resize", this.onResize);
    const flowHeight = this.getViewPortHeight() - 51;
    this.setState({ flowHeight });
    setTimeout(() => {
      this.initModelDetail();
    }, 100);
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.onResize);
    const { dispatch } = this.props;
    dispatch({ type: "FlowChart/clearData" });
  }

  onResize = () => {
    const { flowHeight: oldHeight } = this.state;
    const flowHeight = this.getViewPortHeight() - 51;
    if (this.flowEditRef) this.flowEditRef.editorForceFit("cc");
    if (flowHeight !== oldHeight) {
      this.setState({ flowHeight });
    }
  };

  getEditThis = _this => {
    this.flowEditRef = _this;
  };

  // 通过Id获取信息
  initModelDetail = () => {
    // reset
    this.changeModelVariableRef(null, null, null, true);
    const {
      location: {
        query: { modelid = "", modelId: _mId = "" },
        state: lstate,
      },
      dispatch,
    } = this.props;
    const mId = modelid || _mId;
    if (!mId || !this.flowEditRef) return;
    dispatch({
      type: "FlowChart/getModelDetail",
      payload: { modelId: mId },
    }).then(({ errCode }) => {
      if (errCode === 0) {
        const {
          FlowChartStore: { detailData = {} },
          menuAppStore: { appListAll = [] },
        } = this.props;
        const { modelProperties } = this.state;
        //  // eslint-disable-next-line no-debugger
        //  debugger
        const {
          modelJson = {},
          description,
          modelId,
          name,
          appId,
          key,
          busiId,
          version,
          // formFields = {}
        } = detailData || {};
        // 初始化判断是否请求FormSetupInfo的数据
        if (
          detailData.modelJson?.properties?.formId &&
          detailData.modelJson?.properties?.formname &&
          !detailData.modelJson?.properties?.formFields
        ) {
          dispatch({
            type: "FormSelectModel/FormSetupInfo",
            payload: { formId: detailData.modelJson.properties.formId },
          }).then(({ errCode1, datas }) => {
            if (errCode1 === 0) {
              if (datas === []) {
                message.warn("此表单数据为空");
              }

              // this.getDatas(datas);
              detailData.modelJson.properties.formFields = datas;
            }
          });
          // getDatas(modelProperties.formFields)
        }
        const sampleDetailData = {
          description,
          modelId,
          name,
          key,
          appId,
          busiId,
          version,
        };

        const {
          nodes = [],
          edges = [],
          properties = {},
          groups = [],
        } = modelJson;

        const nodesData = { nodes, edges, groups };
        const newModelProperies = { ...modelProperties, ...properties };
        // const newModelProperies = properties
        // // eslint-disable-next-line no-debugger
        // debugger
        // 画图
        this.flowEditRef.drawModel(nodesData); // 反显数据
        this.setState(
          {
            modelJson,
            modelProperties: newModelProperies,
            sampleDetailData,
            modelForms: getModelForms(newModelProperies, nodes),
          },
          () => {
            this.flowEditRef.editorForceFit("cc");
          },
        );
        // 流程高级设置中可能引用了流程变量
        this.changeModelVariableRef(
          extractVarCodesFromTimeoutSetting(properties.timeoutSetting),
          properties,
          true,
        );
        const { isAdd } = lstate || {};
        if (nodes.length === 0 && !isAdd) {
          this.openNotificationWithIcon("warning", "", `还未配置流程模型`);
        } else {
          nodes
            .filter(n => n.shape === "UserTask" || n.shape === "AuditTask")
            .forEach(userTask => {
              const { model: { properties: _p = {} } = {} } = userTask;
              const { candidateUsers = [], timeoutSetting = {} } = _p;
              // 办理人可能引用了流程变量
              let codes = getCodes(candidateUsers);
              // 用户任务中高级设置中引用的流程变量
              codes = codes.concat(
                extractVarCodesFromTimeoutSetting(timeoutSetting),
              );
              // codes里面可能含有重复的流程变量code值，因此此方法需要进行引用计数
              this.changeModelVariableRef(codes, userTask, true);
            });
        }
        if (appListAll.length === 0) {
          dispatch({ type: "appListMenu/getAppListData" });
        }
      }
    });
  };


  saveFow = (data = {}) => {
    setTimeout(() => {
      const {
        location: {
          query: { modelid = "", modelId = "" },
        },
        dispatch,
      } = this.props;
      const {
        FlowChartStore: { detailData = {} },
      } = this.props;
      const compatModelId = modelId || modelid;
      if (!compatModelId) return;
      const { modelJson, modelProperties, sampleDetailData } = this.state;
      const { nodes = [], edges = [], groups = [] } = data;

      nodes.map(item => {

        if (item.shape === "UserTask") {
          const {mustExpress='0',forcePick='0',objectMeta, ...rest} = item.model.properties ?? {};

         let tmpObjectMeta = objectMeta;
         if (!objectMeta || objectMeta === {} || !objectMeta?.code) {
           tmpObjectMeta = modelProperties?.objectMeta ?? {}
         }
          item.model.properties = {mustExpress,forcePick,objectMeta: tmpObjectMeta, ...rest};
        }
        return item;
      })


      const newModelJson = {
        ...modelJson,
        properties: modelProperties,
        nodes,
        edges,
        groups,
      };
      const startNode = [];
      const endNode = [];
      // const usertaskassignment = []; // 未填写办理人
      // const emptyEdgesNode = [];
      const sameOverrideidItems = [];
      const UserTask = [];
      const overrideidCheck = [];
      const illegalAlertCodeCheck = [];
      const alertCodeDuplicateCheck = [];
      const candidateUsersCheck = []; // 用户任务处理人设置不可为空
      const ScriptTaskErrs = []; // 脚本任务校验错误集
      const signInCheck = []; // 用户任务处理人大于1，签收按钮打开
      const processTimeAfterTimeoutCheck = []; // 任务超时时间不得超过流程超时时间
      const alertTimeAfterTimeoutCheck = []; // 预警时间不得超出超时时间
      const zeroProcessTimeoutCheck = []; // 任务超时时间 不得为 0 0 0
      const zeroProcessWarningCheck = []; // 任务预警时间不得为 0 0 0
      const zeroTimeoutCheck = []; // 任务超时时间 不得为 0 0 0
      const zeroWarningCheck = []; // 任务预警时间不得为 0 0 0

      const isPassd = GroupCheck(nodes,edges,groups);
      if (!isPassd) return;

      const { key: modeKey } = { ...detailData, ...sampleDetailData };
      if (!modePattern.test(modeKey)) {
        this.openNotificationWithIcon(
          "warning",
          "",
          `流程编码输入格式不正确（由字母、数字、下划线、中划线，且以字母或者下划线开头），请修改后保存`,
        );
        if (this.flowEditRef) this.flowEditRef.setItemSelected("", true);
        return;
      }
      const isPass = this.handleDetailCheck(sampleDetailData, checkList);
      if (!isPass) return;
      // 检查流程设置
      validateTimeoutSettings(
        alertTimeAfterTimeoutCheck,
        processTimeAfterTimeoutCheck,
        alertCodeDuplicateCheck,
        illegalAlertCodeCheck,
        modelProperties.timeoutSetting,
        null,
        modelProperties,
        zeroProcessTimeoutCheck,
        zeroProcessWarningCheck,
      );

      nodes.forEach(item => {
        if (item.shape === "StartNoneEvent") {
          const { model: citemModel } = item;
          const { properties = {} } = citemModel || {};
          startNode.push(item);
          if (!pattern.test(properties.overrideid)) {
            overrideidCheck.push(item);
          }
        } else if (item.shape === "EndNoneEvent") {
          const { model: citemModel } = item;
          const { properties = {} } = citemModel || {};
          endNode.push(item);
          if (!pattern.test(properties.overrideid)) {
            overrideidCheck.push(item);
          }
        } else if (item.shape === "UserTask" || item.shape === "AuditTask") {
          const { model: citemModel } = item;
          const { properties = {} } = citemModel || {};
          if (!pattern.test(properties.overrideid)) {
            overrideidCheck.push(item);
            // this.openNotificationWithIcon('warning', '', `${selectLabel}元素编码输入格式不正确，请输入以字母开头，且又字母、数字、下划线组成的编码`);
          }
          if (properties.candidateUsers.length === 0 && properties?.candidateSetNull !== '1') {
            candidateUsersCheck.push(item);
          } else if (properties.candidateUsers.length === 1) {
            const { type } = properties.candidateUsers[0];
            if (
              (type === "ORG" || type === "ROL") &&
              !properties.nodeAuth.signIn
            ) {
              signInCheck.push(item);
            }
          } else if (
            // properties.candidateUsers.length > 1 &&
            !properties.nodeAuth.signIn
          ) {
            signInCheck.push(item);
          }
          const someItem = UserTask.find(citem => {
            return citem.model.properties.overrideid === properties.overrideid;
          });
          if (someItem) {
            sameOverrideidItems.push(someItem);
          }
          UserTask.push(item);
          const { timeoutSetting = {} } = properties;
          validateTimeoutSettings(
            alertTimeAfterTimeoutCheck,
            processTimeAfterTimeoutCheck,
            alertCodeDuplicateCheck,
            illegalAlertCodeCheck,
            timeoutSetting,
            modelProperties.timeoutSetting,
            item,
            zeroTimeoutCheck,
            zeroWarningCheck,
          );
        } else if (item.shape === "ScriptTask") {
          const { model: citemModel, label } = item;
          if (!citemModel?.properties?.baseInfo?.code) {
            ScriptTaskErrs.push(`${label}节点编码不能为空，请修改后保存`);
          }
          if (!citemModel?.properties?.scriptConf?.scriptFormat) {
            ScriptTaskErrs.push(`${label}脚本类型不能为空，请修改后保存`);
          }
          if (!citemModel?.properties?.scriptConf?.scriptText) {
            ScriptTaskErrs.push(`${label}脚本不能为空，请修改后保存`);
          }
        } else if (item.shape === "ServiceTask") {
          const { model: citemModel, label } = item;
          if (!citemModel?.properties?.baseInfo?.code) {
            ScriptTaskErrs.push(`${label}节点编码不能为空，请修改后保存`);
          }
          if (!citemModel?.properties?.serviceConf?.type) {
            ScriptTaskErrs.push(`${label}服务类型不能为空，请修改后保存`);
          }
          if (!citemModel?.properties?.serviceConf?.expression) {
            ScriptTaskErrs.push(`${label}表达式不能为空，请修改后保存`);
          }
          if (!citemModel?.properties?.serviceConf?.resultVariable) {
            ScriptTaskErrs.push(`${label}结果变量不能为空，请修改后保存`);
          }
        }
      });
      if (startNode.length > 1 || startNode.length === 0) {
        this.openNotificationWithIcon(
          "warning",
          "",
          "流程开始事件至少有一个，且只能有一个",
        );
        return;
      }
      if (endNode.length > 1 || endNode.length === 0) {
        this.openNotificationWithIcon(
          "warning",
          "",
          "流程结束事件至少有一个，且只能有一个",
        );
        return;
      }
      if (ScriptTaskErrs.length > 0) {
        this.openNotificationWithIcon("warning", "", ScriptTaskErrs[0]);
        return;
      }
      if (overrideidCheck.length > 0) {
        const { label } = overrideidCheck[0];
        this.openNotificationWithIcon(
          "warning",
          "",
          `"${label}"节点编码输入格式不正确，请修改后保存`,
        );
        if (this.flowEditRef)
          this.flowEditRef.setItemSelected(overrideidCheck[0].id, true);
        return;
      }

      // 添加留空 -- 去掉校验
      if (candidateUsersCheck.length > 0) {
        const { label } = candidateUsersCheck[0];
        this.openNotificationWithIcon(
          "warning",
          "",
          `"${label}"办理人设置不可为空`,
        );
        if (this.flowEditRef)
          this.flowEditRef.setItemSelected(candidateUsersCheck[0].id, true);
        return;
      }
      if (signInCheck.length > 0) {
        const { label } = signInCheck[0];
        this.openNotificationWithIcon(
          "warning",
          "",
          `"${label}"办理人数大于 1 时，请启用高级设置中的“签收”功能`,
        );
        if (this.flowEditRef)
          this.flowEditRef.setItemSelected(signInCheck[0].id, true);
        return;
      }
      const timeoutError = getTimeoutErrorInfo(
        alertCodeDuplicateCheck,
        alertTimeAfterTimeoutCheck,
        processTimeAfterTimeoutCheck,
        illegalAlertCodeCheck,
        zeroProcessTimeoutCheck,
        zeroProcessWarningCheck,
        zeroTimeoutCheck,
        zeroWarningCheck,
      );
      if (timeoutError) {
        const { notificationArgs, selectId } = timeoutError;
        this.openNotificationWithIcon(...notificationArgs);
        if (this.flowEditRef) this.flowEditRef.setItemSelected(selectId, true);
        return;
      }
      if (sameOverrideidItems.length > 0) {
        const { label } = sameOverrideidItems[sameOverrideidItems.length - 1];
        this.openNotificationWithIcon(
          "warning",
          "",
          `"${label}"元素编码不唯一,请修改后保存`,
        );
        if (this.flowEditRef)
          this.flowEditRef.setItemSelected(sameOverrideidItems[0].id, true);
        return;
      }
      dispatch({
        type: "FlowChart/saveModel",
        payload: {
          ...detailData,
          ...sampleDetailData,
          compatModelId,
          modelJson: newModelJson,
        },
      }).then(({ errCode, errMsg }) => {
        if (errCode === 0) {
          this.openNotificationWithIcon(
            "success",
            "",
            "保存成功，若要生效，请重新部署",
          );
        } else {
          this.openNotificationWithIcon("error", "", errMsg || "保存失败");
        }
      });
    }, 300);
  };

  handleDetailCheck = (data = {}, checkLists = []) => {
    let isPass = true;
    for (let i = 0; i < checkLists.length; i += 1) {
      if (!data[checkLists[i].key]) {
        isPass = false;
        this.openNotificationWithIcon("warning", "", checkLists[i].msg);
        if (this.flowEditRef) this.flowEditRef.setItemSelected(null, true); // 清除选中
        break;
      }
    }
    return isPass;
  };

  // input选择框会触发的方法 关联Pannel文件
  handleModelPropChange = (modelProperties, cb) => {
    if (cb) {
      this.setState({ modelProperties }, cb);
    } else {
      this.setState({ modelProperties });
    }
  };

  updateModelForms = () => {
    if (this.flowEditRef) {
      const nodes = (this.flowEditRef.getNodes() || []).map(
        ({ model }) => model,
      );
      const { modelProperties } = this.state;
      this.setState({ modelForms: getModelForms(modelProperties, nodes) });
    }
  };

  handleDetailChange = changeData => {
    const { sampleDetailData } = this.state;
    this.setState({ sampleDetailData: { ...sampleDetailData, ...changeData } });
  };

  reBack = () => {
    Modal.confirm({
      title: "您有未保存的更改",
      content: "您想如何处理未保存的更改？",
      cancelText: "放弃更改",
      okText: "继续编辑",
      onOk() {},
      onCancel() {
        router.push("/flowmanage/flowconfigure");
      },
    });
  };

  updateDrawData = (key, value) => {
    if (this.flowEditRef) {
      this.flowEditRef.updateDrawData(key, value);
    }
  };

  getSelectedModel = () => {
    if (this.flowEditRef) {
      return this.flowEditRef.getSelectedModel();
    } else {
      return [];
    }
  };

  checkInputUrl = (data) => {
    const {
      dispatch,
    } = this.props;
    // eslint-disable-next-line no-debugger
    return dispatch({
      type: "FlowChart/checkFlowChartUrl",
      payload: {
        url: data,
      },
    })
  }
  /* eslint-disable*/
  testEvent = (data) => {
    const {
      dispatch,
    } = this.props;
    return dispatch({
      type: "FlowChart/testEvent",
      payload: {
        requestUrl: data.config,
        requestJsonParams:data.requestBody
      },
    })
  }
   /* eslint-disable*/

  detailpannelContent = (selectedModel, modelProperties) => {
    const { modelVariableRef, modelForms } = this.state;
    const { shape } = selectedModel || {};
    const {
      FlowChartStore: { candidateGroupsData = []  },
      FlowHandleStore:{customTitleList=[]},
      menuAppStore,
      dispatch,
    } = this.props;
    const { sampleDetailData } = this.state;
    const drawData = this.flowEditRef?.getDrawData();
    const { appListAll = [], appBusinessObjAll = {} } = menuAppStore;
    const title = shape ? titleObj[shape] : "";
    return (
      <React.Fragment>
        {/* 节点 */}
        <NodeSelected
          title={title}
          updateGraph={this.updateDrawData}
          dispatch={dispatch}
          changeModelVariableRef={this.changeModelVariableRef}
          modelVariableRef={modelVariableRef}
          selectedModel={selectedModel}
          modelProperties={modelProperties}
          handleModelPropChange={this.handleModelPropChange}
          candidateGroupsData={candidateGroupsData}
          getNodes={this.getNodes}
          disable={false}
          appId={sampleDetailData.appId}
          busiId={sampleDetailData.busiId}
          modelForms={modelForms}
          updateModelForms={this.updateModelForms}
          flowEditRef={this.flowEditRef}
          customTitleList={customTitleList}
          checkInputUrl={this.checkInputUrl}
          testEvent={this.testEvent}
          drawData={drawData}
          // filList={filList}
        />
        {/* 边 */}
        <EdgeSelected
          title={title}
          updateGraph={this.updateDrawData}
          selectedModel={selectedModel}
          modelProperties={modelProperties}
          handleModelPropChange={this.handleModelPropChange}
          disable={false}
        />
        {/* 画布 */}
        <CanvasSelected
          appId={sampleDetailData.appId}
          changeModelVariableRef={this.changeModelVariableRef}
          dispatch={dispatch}
          updateGraph={this.updateDrawData}
          modelProperties={modelProperties}
          modelVariableRef={modelVariableRef}
          handleModelPropChange={this.handleModelPropChange}
          disable={false}
          sampleDetailData={sampleDetailData}
          handleDetailChange={this.handleDetailChange}
          appList={appListAll}
          appBusinessObj={appBusinessObjAll}
          modelForms={modelForms}
          updateModelForms={this.updateModelForms}
          isCanvas
          flowEditRef={this.flowEditRef}
          selectedModel={selectedModel}
          customTitleList={customTitleList}
          // filList={filList}
        />
        {/* 分组 */}
        <GroupSelected
          title={title}
          updateGraph={this.updateDrawData}
          selectedModel={selectedModel}
          modelProperties={modelProperties}
          handleModelPropChange={this.handleModelPropChange}
          disable={false}
        />
      </React.Fragment>
    );
  };

  render() {
    const { loading } = this.props;
    const { flowHeight, modelProperties } = this.state;
    const height = flowHeight > 450 ? flowHeight : 450;
    const dataLoading = loading.effects["FlowChart/getModelDetail"];
    return (
      <Spin spinning={dataLoading} delay={300}>
        <FlowEditor
          height={height}
          className={styles.flowchart}
          getEditThis={this.getEditThis}
          onSave={this.saveFow}
          onBack={this.reBack}
          detailpannelContent={selected =>
            this.detailpannelContent(selected, modelProperties)
          }
        />
      </Spin>
    );
  }
}

export default FlowChart;
